﻿package com{
	import flash.events.*;
	import flash.display.*;
	import flash.net.*;
	import flash.media.*;
	import flash.system.*;
	import flash.utils.ByteArray;
	import flash.utils.Endian;
	import flash.utils.Timer;
	import flash.external.ExternalInterface;
	import flash.text.TextField;

	/**
	 *  兼容加载avm1和avm2的swf文件
	 * @author harriet
	 */
	public class SwfLoader extends Sprite {
		protected var _url:String;
		public var loader:Loader;
		public static const Complete:String = "load_complete";
		public static const Progress:String = "load_progress";

		public function SwfLoader(s:String) {
			_url = s;
			executeLoad();
		}
		private function executeLoad():void {
			var appDomain:ApplicationDomain = new ApplicationDomain(null);
			var ldrContext:LoaderContext=new LoaderContext(false,appDomain);
			var request:URLRequest=new URLRequest(_url);
			loader = new Loader();
			addChild(loader);
			loader.load(request,ldrContext);
			loader.contentLoaderInfo.addEventListener(Event.COMPLETE, playSwf, false, 0, true);
			loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onError);		
			//loader.contentLoaderInfo.addEventListener(Event.,playSwf,false,0,true);
		}
		
		private var loadTxt:TextField;
		private function playSwf(e:Event):void 
		{
			loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, playSwf);
			
			var loaderinfo:LoaderInfo = e.target as LoaderInfo;  
			var inputBytes:ByteArray = ByteArray(loaderinfo.bytes);
			inputBytes.endian = Endian.LITTLE_ENDIAN;

			if (isCompressed(inputBytes))
			{
				uncompress(inputBytes);
			} 
			
			var version:uint = uint(inputBytes[3]); 
			if (version <= 10) 
			{ 
				if (version == 8 || version == 9 || version == 10)
				{
					flagSWF9Bit(inputBytes);
				}
				else if (version <= 7) 
				{
					insertFileAttributesTag(inputBytes);
				}
				updateVersion(inputBytes, 9);
			}

			// 第二个Loader用于加载第一个Loader加载进来的bytes   
			var loader2:Loader = new Loader(); 
			loader2.contentLoaderInfo.addEventListener(Event.COMPLETE, loader2Complete); 
			//loader2.contentLoaderInfo.addEventListener(Event.INIT, initSwf, false, 0, true);
			loader2.loadBytes(inputBytes);   	
			
		}
		/*private function initSwf(e:Event):void
		{
			dispatchEvent(new LoaderEvent(Progress,e.target));
		}*/
		private function loader2Complete(e:Event):void
		{
			dispatchEvent(new LoaderEvent(Complete,e.target.content));
		}
		private function flagSWF9Bit(bytes:ByteArray):void
		{
			var pos:uint = findFileAttributesPosition(getBodyPosition(bytes), bytes);
			if (!isNaN(pos)) 
			{
				bytes[pos + 2] |= 0x08;
			}
		}
		
		private function findFileAttributesPosition(offset:uint, bytes:ByteArray):uint
		{
			bytes.position = offset; 
			try 
			{
				for (;; ) 
					{
						var byte:uint = bytes.readShort();
						var tag:uint = byte >>> 6;
						if (tag == 69) 
						{
							return bytes.position - 2;
						}
						var length:uint = byte & 0x3f;
						if (length == 0x3f) 
						{
							length = bytes.readInt();
						}
						bytes.position += length;
					}
			}
			catch (e:Error)
			{
			} 
			return NaN;
		}
		private function insertFileAttributesTag(bytes:ByteArray):void
		{
			var pos:uint = getBodyPosition(bytes);
			var afterBytes:ByteArray = new ByteArray();
			afterBytes.writeBytes(bytes, pos);
			bytes.length = pos;
			bytes.position = pos;
			bytes.writeByte(0x44);
			bytes.writeByte(0x11);
			bytes.writeByte(0x08);
			bytes.writeByte(0x00);
			bytes.writeByte(0x00);
			bytes.writeByte(0x00);
			bytes.writeBytes(afterBytes);
			afterBytes.length = 0;
		}

		private function updateVersion(bytes:ByteArray, version:uint):void
		{
			bytes[3] = version;
		}

		private function getBodyPosition(bytes:ByteArray):uint
		{
			var result:uint = 0; 
			result += 3; // FWS/CWS
			result += 1; // version(byte)
			result += 4; // length(32bit-uint) 
			var rectNBits:uint = bytes[result] >>> 3;
			result += (5 + rectNBits * 4) / 8; // stage(rect) 
			result += 2; 
			result += 1; // frameRate(byte)
			result += 2; // totalFrames(16bit-uint) 
			return result;
		}  
		/**
			* 
			* @param bytes
			* @return 
			* 
			*/ 
		private function isCompressed(bytes:ByteArray):Boolean
		{
			//trace(bytes.toString());
			return bytes[0] == 0x43;
		} 

		private function uncompress(bytes:ByteArray):void
		{
			var cBytes:ByteArray = new ByteArray();
			cBytes.writeBytes(bytes, 8);
			bytes.length = 8;
			bytes.position = 8;
			cBytes.uncompress();
			bytes.writeBytes(cBytes);
			bytes[0] = 0x46;
			cBytes.length = 0;
		} 
		
		
		private function onError(e:IOErrorEvent):void {
			//Js.debug("加载失败!");
			dispatchEvent(new Event("error"));
		}
		public function get url():String {
			return _url;
		}
		public function set url(s:String):void {
			_url =s;
		}
	}
}